{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## PmodOLED Example\n",
    "\n",
    "## Contents\n",
    "\n",
    "* [Introduction](#Introduction)\n",
    "* [Setup the board and PmodOLED](#Setup-the-board-and-PmodOLED)\n",
    "* [Write to the PmodOLED](#Write-to-the-PmodOLED)\n",
    "* [Draw some patterns](#Draw-some-patterns)\n",
    "* [Create a new Python function](#Create-a-new-Python-function)\n",
    "* [Putting it all together](#Putting-it-all-together)\n",
    "\n",
    "----\n",
    "\n",
    "## Introduction\n",
    "This demonstration shows how to use the PmodOLED using the PYNQ-Z1 or PYNQ-Z2 board.\n",
    "\n",
    "----\n",
    "\n",
    "## Setup the board and PmodOLED, and load the overlay\n",
    "### Connect the PmodOLED to the board.\n",
    "In this example the ***PmodOLED*** should be connected to ***PMODA.***"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pynq.overlays.base import BaseOverlay\n",
    "base = BaseOverlay(\"base.bit\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pynq.lib.pmod import Pmod_OLED\n",
    "# Connect to PMODA\n",
    "pmod_oled = Pmod_OLED(base.PMODA)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "## Write to the PmodOLED"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pmod_oled.clear()\n",
    "pmod_oled.write('     Welcome\\n       to\\n      PYNQ!')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### You should now see the text output on the OLED. \n",
    "\n",
    "Try another message:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "pmod_oled.clear()\n",
    "pmod_oled.write('Python and Zynq\\nProductivity &  performance')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Clear the display when finished."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pmod_oled.clear()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "System information can be captured and stored in Python variables, and written to the peripheral."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hostname = !hostname\n",
    "ip_addr = !hostname -I\n",
    "pmod_oled.write(hostname[0] + \"\\nIP:\" + ip_addr[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pmod_oled.clear()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "----\n",
    "## Draw some patterns\n",
    "The PmodOLED includes some built in functions running in C code on the IOP. For drawing lines and rectangles, the `draw_line()` `draw_rectangle()` functions are provided.\n",
    "\n",
    "The OLED display area is 32 pixels x 128 pixels.\n",
    "\n",
    "\n",
    "### Draw a line\n",
    "A line can be drawn by specifying two co-ordinates: pmod_oled.draw_line(x1, y1, x2,y2)\n",
    "You can execute the next cell, or change the co-ordinates and execute the cell below to draw another line. \n",
    "\n",
    "`pmod_oled.clear()` should be called to clear the display if you do not want lines drawn on top of previous lines. If the bitstream is reloaded the display will also be cleared.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pmod_oled.draw_line(0,0,128,32)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pmod_oled.draw_line(0,32,128,0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pmod_oled.clear()\n",
    "pmod_oled.draw_line(64,0,64,32)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Clear the display when finished. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pmod_oled.clear()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Draw a rectangle\n",
    "You can draw a rectangle in a similar way by specifying two co-ordinates: pmod_oled.draw_line(x1, y1, x2,y2). This will draw a rectangle using the two points as opposite corners"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pmod_oled.draw_rect(60,5,80,25)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pmod_oled.draw_rect(105,0,120,28)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Clear the display when finished."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pmod_oled.clear()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "----\n",
    "## Create a new Python function\n",
    "\n",
    "More functions could be implemented in the C code running on the IOP to generate other patterns. The existing functions can also be extended in Python to add more functionality. \n",
    "\n",
    "The following cell defines a function to draw circles on the PmodOLED."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import math\n",
    "# Draw a circle\n",
    "# Screen resolution is 128x32\n",
    "def draw_circle(cx,cy, r):\n",
    "    for i in range (0, 360):\n",
    "        x = cx + r * math.cos(i*math.pi/180)\n",
    "        if(x > 127):\n",
    "            x = 127\n",
    "        if(x<0):\n",
    "            x = 0\n",
    "        y = cy + r * math.sin(i*math.pi/180)\n",
    "        if(y>31):\n",
    "            y = 31\n",
    "        if(y<0):\n",
    "            y = 0\n",
    "        pmod_oled.draw_line(int(x),int(y),int(x+1),int(y))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Draw the circle\n",
    "You can draw a circle by using the function which has just been created, and by specify a co-ordinate and the radius. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pmod_oled.clear()\n",
    "draw_circle(64,16,15)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Remember the display is 128x32 pixels. If the circle exceeds the display area it will be clipped. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pmod_oled.clear()\n",
    "draw_circle(64,32,15)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Additional functionality can be added easily in Python, but note that functions in Python will be slower than using the C functions running directly on the IOP. (In this case, the circle co-ordinates are calculated in Python, and the IOP draw_line() is called 360 times which is much slower than simply drawing a single line using the draw_line() function.)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "----\n",
    "## Putting it all together\n",
    "Draw some patterns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pmod_oled.clear()\n",
    "\n",
    "pmod_oled.draw_line(0,0,128,32)\n",
    "\n",
    "pmod_oled.draw_rect(60,5,80,25)\n",
    "pmod_oled.draw_rect(105,0,120,28)\n",
    "\n",
    "draw_circle(16,16,16)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pmod_oled.clear()\n",
    "\n",
    "for i in range (0,9):\n",
    "    draw_circle(16,16,i*2)\n",
    "    \n",
    "for i in range (0,6):\n",
    "    draw_circle(48,16,1+i*3)\n",
    "\n",
    "for i in range (0,5):\n",
    "    draw_circle(80,16,i*4)\n",
    "    \n",
    "for i in range (0,4):\n",
    "    draw_circle(111,16,1+i*5)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
